# -*- coding: utf-8 -*-
'''
这是一个用于索引的包。开启一个后台线程，时时刻刻的扫描全局变量。
'''
import sys
from autocompletion.syntaxana import *
import noval.util.utils as utils
import noval.util.strutils as strutils
from noval.python.parser.utils import py_sorted
import threading
import time

indexList = []
autoConvertChPuncs = True
kwdTuple = ('if', 'else', 'elif', 'while', 'for', 'with', 'assert')
autoCompInputTimesList = []  # 输入次数列表

charStr = ''  # 获取的一切字符都连缀在这里。
charReplaceDic = getReplacingDic()



def getReplacingChar(c:str)->str:
    if (c in charReplaceDic.keys()):
        return charReplaceDic[c]
    else:
        return c


def addVariableTypeTag(varList, typeTag):
    for i, item in enumerate(varList):
        item = item.split(':')[0]
        varList[i] = item + typeTag
    return varList


def extendSupportedStr(st):
    s = set(st + charStr)
    for i in ['+', '-', '*', '/', ' ', '\t', ':', '(', ')']:
        if (i in s):
            s.remove(i)
    return ''.join(s)


def getCodeView():
    from noval import GetApp
    try:
        current_editor = GetApp().MainFrame.GetNotebook().get_current_editor()  # 获取编辑窗口。
        if current_editor is not None:
            return   current_editor.GetView()
    except:
        pass
    return None
    
def getCodeCtrl():
    from noval import GetApp
    
    try:
        current_editor = GetApp().MainFrame.GetNotebook().get_current_editor()  # 获取编辑窗口。
        if current_editor is not None:
            current_docview = current_editor.GetView()
            if current_docview:
                ctrl = current_docview.GetCtrl()  # 获取当前窗口的文本控件。
                return ctrl
    except:
        pass
    return None

def bindKeyEvent(indexer):# 将当前的编辑窗口CodeCtrl的任何键按下绑定到刷新更新时间上。
    try:
        ctrl = getCodeCtrl()
        ctrl.bind('<Key>', indexer.updateLastKeyPressedTime,'+')
    except:
        import traceback
        traceback.print_exc()
        return None


class BackgroundIndexer():
    def __init__(self, debugging=True):
        self.bgIndexing = True
        self.currentCodeCtrl = None

        self.debugging = debugging
        self.lastIndexedTime = time.time()
        self.lastKeyPressedTime = time.time()
        #####以下是与语法扫描有关的量
        self.indexList = []
        self.globalFuncSet = []
        bindKeyEvent(self)
        self.indexingThread = threading.Thread(target=self.indexLoop)
        self.indexingThread.setDaemon(True)
        self.indexingThread.start()

    def updateLastKeyPressedTime(self, event):
        '''
        记录上一次按键的时间。这样可以避免过于频繁的扫描。
        '''
        self.lastKeyPressedTime = time.time()

    def weightedSort(self, globalValues, localValues):
        # 带有权重的分类排序,目前没用上
        loc = py_sorted(localValues, cmp_func=strutils.caseInsensitiveCompare)
        glo = py_sorted(globalValues, cmp_func=strutils.caseInsensitiveCompare)
        return glo + loc

    def getLocalVarList(self, line):
        if (len(self.indexList) > line):
            return self.indexList[line - 1]
        return []

    def printDebug(self, *args):  
        '''
        在调试状态下才能有输出。
        '''
        if (self.debugging):
            print(*args)
        else:
            pass

    def storage(self):
        '''
        [!TODO],这是一个保存索引或者输入数据的函数。但是暂时没有使用。
        '''
        global autoCompInputTimesList
        autoCompInputTimesList = []
        return

    def changeCodeCtrl(self, codeCtrl):
        '''
        每次切换代码编辑窗口时，都会对相应的编辑窗口绑定事件。作用是检测按键输入并且进行自动补全。
        '''
        self.currentCodeCtrl = codeCtrl
        try:
            bindKeyEvent(self)
            self.lastIndexedTime = time.time()
            self.doIndex()
        except:
            import traceback
            traceback.print_exc()

    def indexLoop(self):
        '''
        在这个循环中不断扫描代码。
        '''
        while (1):
            time.sleep(3)
            codeCtrl = getCodeCtrl()
            
            if codeCtrl != None:
                if codeCtrl != self.currentCodeCtrl:
                    self.changeCodeCtrl(codeCtrl)
            else:
                continue
            
            if self.lastIndexedTime < self.lastKeyPressedTime:
                try:
                    code_view = getCodeView()
                    file_name = code_view.GetDocument().GetFilename()
                    if file_name.endswith('.py'):
                        # 如果是python脚本，就调用词法分析库；否则就使用codeview的默认索引。
                        self.lastIndexedTime = time.time()
                        self.doIndex()
                    else:
                        code_view.lexParse()
                except:
                    import traceback
                    traceback.print_exc()
                    continue
                    
    def printInfo(self):
        for i in range(len(self.indexList)):
            for j in range(len(self.indexList[i])):
                if (self.indexList[i][j].find("#") != -1):
                    self.indexList[i][j] = ''
        #         charStr += self.indexList[i][j]
            self.printDebug(i, self.indexList[i])
        f = open('temp.log', 'w')
        for i in range(len(self.indexList)):
            f.write(str(self.indexList[i]) + '\n')
        f.close()
        
    def doIndex(self):
        '''
        索引的主函数，在辅助线程中运行。但是，目前功能并不完善。
        '''
        global kwdTuple, indexList,charStr
        testing = self.debugging
        if (self.bgIndexing == False):  # 如果关闭索引功能的话，线程开着，只会不断等待。
            pass

        t = getText()  # 获取打开的文件数组,每个元素是一行。
        if t==[]:
            return
        f = regularize(t)
        fileRowNum = f[-1].pos + 1
        self.printDebug(f, f[-1].pos)
        if (f == None):
            self.printDebug('f为空。。。。。。。。。。')
            pass
        inStaticFunction = False
        indexList = []
        funcSet = set()  # 集合，列出所有的函数。
        localKeyList = [[]] * fileRowNum  #
        utils.get_logger().debug("开始补全扫描……")
        self.printDebug(f)
        for row in f:
            i = row.pos
            currentRow = row.text
            currentIndent = row.indent
            if (currentRow.startswith('def ')):  # 注意，这里有个空格！！！！！！否则会和一堆def开头的变量名撞车。
                self.printDebug(i, "find a def!!!!!!!!!!!", currentRow, currentRow.endswith(':'))
                args = getFuncArgs(currentRow)

                funcName = getFuncName(currentRow)

                localKeyList[i] = [funcName] + args
                self.printDebug(i, "函数名：", funcName)
                if (funcName not in funcSet):
                    funcSet.add(funcName)
                    inStaticFunction = True

                    continue
            elif inStaticFunction:  # 如果在函数中，就这样解析。
                if (i >= 1):
                    if (localKeyList[i - 1][0] == funcName):
                        localKeyList[i] = localKeyList[i - 1].copy()  # 如果在同一个函数中，需要复制一下，
                    else:# 不在同一个函数中的时候
                        self.printDebug(i, currentIndent, localKeyList[i][0], funcName)
                        localKeyList[i][0] = funcName
                        localKeyList[i] += args

                else:
                    localKeyList[i] = [funcName, args]

                if (currentRow.startswith(kwdTuple) == False):  # 如果当前行不以关键字开始的话，就这样执行分析。当然，(for除外)
                    # 这里的命令可以分为两类：命令类（只调用无返回）以及赋值类。
                    sym, content, outer = getBracketedContent(currentRow)

                    if (outer.find('=') != -1):  # 这一个函数是判断赋值语句的。outer代表括号之外的内容。
                        crl = getLocalVarNames(outer)

                        if (crl != []):
                            localKeyList[i] += crl

                elif (currentRow.startswith('for')):

                    localKeyList[i] += getForVariables(currentRow)

                funcName = localKeyList[i][0]
                localKeyList[i] = list(set(localKeyList[i]))
                ind = localKeyList[i].index(funcName)
                localKeyList[i][ind] = localKeyList[i][0]
                localKeyList[i][0] = funcName

        self.indexList = localKeyList
        self.globalFuncSet = funcSet
        self.printInfo()




if __name__ == "__main__":
    b = BackgroundIndexer()
    while (1):
        time.sleep(1)
